package main

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/jmoiron/sqlx"
	"gopkg.in/yaml.v3"
	"log"
	"net/http"
	"os"
	"strings"

	_ "dm"
	"github.com/gin-gonic/gin"
)

func main() {
	// 加载配置
	config, err := LoadConfig("db.yml")
	if err != nil {
		log.Fatalf("配置文件加载失败: %v", err)
	}

	// 初始化数据库服务
	dbSvc, err := NewDMDBService(config.Database.DmDsn)
	if err != nil {
		log.Fatalf("初始化数据库服务失败: %v", err)
	}

	// 初始化Gin
	router := gin.Default()

	// 注入数据库服务中间件
	router.Use(func(c *gin.Context) {
		c.Set("dbService", dbSvc)
		c.Next()
	})

	SetupRoutes(router)

	// 启动服务
	addr := fmt.Sprintf(":%d", config.Server.Port)
	log.Printf("启动服务器 %s", addr)
	if err := router.Run(addr); err != nil {
		log.Fatalf("无法启动服务器: %v", err)
		os.Exit(1)
	}
}

type Config struct {
	Server struct {
		Port int `yaml:"port"`
	} `yaml:"server"`
	Database struct {
		Default string `yaml:"default"`
		DmDsn   string `yaml:"dm_dsn"`
	} `yaml:"database"`
}

func LoadConfig(filename string) (*Config, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	var config Config
	if err := yaml.Unmarshal(data, &config); err != nil {
		return nil, err
	}

	return &config, nil
}

type FetchRequest struct {
	DBName    string `json:"db_name" binding:"required"`
	TableName string `json:"table_name" binding:"required"`
	Limit     int    `json:"limit"`
}

type GenerateSQLRequest struct {
	DBName    string                   `json:"db_name" binding:"required"`
	TableName string                   `json:"table_name" binding:"required"`
	Data      []map[string]interface{} `json:"data" binding:"required"`
}

func FetchData(c *gin.Context) {
	var req FetchRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Limit <= 0 {
		req.Limit = 10
	}

	dbSvc, ok := c.MustGet("dbService").(DatabaseService)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库服务不可用"})
		return
	}

	data, err := dbSvc.FetchData(c.Request.Context(), req.TableName, req.Limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"data": data})
}

func GenerateInitSQL(c *gin.Context) {
	var req GenerateSQLRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if len(req.Data) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "空数据"})
		return
	}

	// 生成建表SQL
	var columns []string
	for col := range req.Data[0] {
		columns = append(columns, col)
	}

	sql := fmt.Sprintf("CREATE TABLE %s (\n", req.TableName)
	for i, col := range columns {
		sql += fmt.Sprintf("  %s VARCHAR(255)", col)
		if i < len(columns)-1 {
			sql += ",\n"
		}
	}
	sql += "\n);\n\n"

	// 生成插入数据SQL
	for _, row := range req.Data {
		var cols []string
		var vals []string
		for col, val := range row {
			cols = append(cols, col)
			vals = append(vals, fmt.Sprintf("'%v'", strings.ReplaceAll(fmt.Sprintf("%v", val), "'", "''")))
		}
		sql += fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s);\n",
			req.TableName, strings.Join(cols, ", "), strings.Join(vals, ", "))
	}

	c.JSON(http.StatusOK, gin.H{"sql": sql})
}

// DatabaseService 定义基础数据库服务接口::定义达梦数据库操作接口
type DatabaseService interface {
	Connect(dsn string) error
	Close() error
	Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	Queryx(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error)
	Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error)

	GetTables(ctx context.Context, dbName string) ([]map[string]interface{}, error)
	DropColumn(ctx context.Context, tableName, columnName string) error
	AddColumn(ctx context.Context, tableName, columnName, columnType, comment string) error
	FetchData(ctx context.Context, tableName string, limit int) ([]map[string]interface{}, error)
}

// DMDBService 实现达梦数据库服务
type DMDBService struct {
	db *sqlx.DB
}

func NewDMDBService(dsn string) (*DMDBService, error) {
	s := &DMDBService{}
	if err := s.Connect(dsn); err != nil {
		return nil, err
	}
	return s, nil
}

func (s *DMDBService) Connect(dsn string) error {
	db, err := sqlx.Connect("dm", dsn)
	if err != nil {
		return err
	}
	s.db = db
	return nil
}

func (s *DMDBService) Close() error {
	return s.db.Close()
}

func (s *DMDBService) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
	return s.db.QueryContext(ctx, query, args...)
}

func (s *DMDBService) Queryx(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error) {
	return s.db.QueryxContext(ctx, query, args...)
}

func (s *DMDBService) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	return s.db.ExecContext(ctx, query, args...)
}

// GetTables 获取数据库表列表
func (s *DMDBService) GetTables(ctx context.Context, dbName string) ([]map[string]interface{}, error) {
	query := fmt.Sprintf("SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = '%s'", dbName)
	rows, err := s.Query(ctx, query)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch data: %w", err)
	}
	defer func(rows *sql.Rows) {
		err := rows.Close()
		if err != nil {
			log.Printf("failed to close rows: %v", err)
		}
	}(rows)

	results, err := row(rows)
	if err != nil {
		return make([]map[string]interface{}, 0), err
	}

	return results, nil
}

// AddColumn 添加表字段
func (s *DMDBService) AddColumn(ctx context.Context, tableName, columnName, columnType, comment string) error {
	// 执行添加列操作
	str := fmt.Sprintf("ALTER TABLE %s ADD %s %s", tableName, columnName, columnType)
	_, err := s.Exec(ctx, str)
	if err != nil {
		return fmt.Errorf("failed to add column: %w", err)
	}

	// 添加注释
	if comment != "" {
		commentSQL := fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'",
			tableName, columnName, strings.ReplaceAll(comment, "'", "''"))
		_, err = s.Exec(ctx, commentSQL)
		if err != nil {
			return fmt.Errorf("failed to add column comment: %w", err)
		}
	}

	return nil
}

// DropColumn 删除表字段
func (s *DMDBService) DropColumn(ctx context.Context, tableName, columnName string) error {
	// 执行添加列操作
	str := fmt.Sprintf("ALTER TABLE %s DROP %s %s", tableName, columnName)
	_, err := s.Exec(ctx, str)
	if err != nil {
		return fmt.Errorf("failed to add column: %w", err)
	}

	return nil
}

// FetchData 获取表数据
func (s *DMDBService) FetchData(ctx context.Context, tableName string, limit int) ([]map[string]interface{}, error) {
	query := fmt.Sprintf("SELECT * FROM %s WHERE ROWNUM <= %d", tableName, limit)
	rows, err := s.Query(ctx, query)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch data: %w", err)
	}
	defer func(rows *sql.Rows) {
		err := rows.Close()
		if err != nil {
			log.Printf("failed to close rows: %v", err)
		}
	}(rows)

	results, err := row(rows)
	if err != nil {
		return make([]map[string]interface{}, 0), err
	}

	return results, nil
}

// row 将查询结果转为 `[]map[string]interface{}` 并返回
func row(rows *sql.Rows) ([]map[string]interface{}, error) {
	var results []map[string]interface{}

	// 获取列名
	columns, err := rows.Columns()
	if err != nil {
		return nil, fmt.Errorf("failed to get columns: %w", err)
	}

	// 创建一个切片来存储指向结果的指针
	values := make([]interface{}, len(columns))
	valuePrs := make([]interface{}, len(columns))
	for i := range values {
		valuePrs[i] = &values[i]
	}

	// 遍历每一行
	for rows.Next() {
		// 扫描行数据到 values 切片
		if err := rows.Scan(valuePrs...); err != nil {
			return nil, fmt.Errorf("failed to scan row: %w", err)
		}

		// 创建一个新的 map 来存储当前行的数据
		row := make(map[string]interface{})
		for i, col := range columns {
			var v interface{}
			val := values[i]
			b, ok := val.([]byte)
			if ok {
				v = string(b)
			} else {
				v = val
			}
			row[col] = v
		}

		// 将当前行的数据添加到结果切片中
		results = append(results, row)
	}
	return results, nil
}

type DropColumnRequest struct {
	DBName     string `json:"db_name" binding:"required"`
	TableName  string `json:"table_name" binding:"required"`
	ColumnName string `json:"column_name" binding:"required"`
}

type AddColumnRequest struct {
	DBName     string `json:"db_name" binding:"required"`
	TableName  string `json:"table_name" binding:"required"`
	ColumnName string `json:"column_name" binding:"required"`
	ColumnType string `json:"column_type" binding:"required"`
	Comment    string `json:"comment"`
}

type AddCommentRequest struct {
	DBName    string `json:"db_name" binding:"required"`
	TableName string `json:"table_name" binding:"required"`
	Column    string `json:"column"`
	Comment   string `json:"comment" binding:"required"`
}

func GetTables(c *gin.Context) {
	dbName := c.Query("db_name")

	dbSvc, ok := c.MustGet("dbService").(DatabaseService)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库服务不可用"})
		return
	}

	tables, err := dbSvc.GetTables(c.Request.Context(), dbName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"tables": tables})
}

func DropColumn(c *gin.Context) {
	var req DropColumnRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	dbSvc, ok := c.MustGet("dbService").(DatabaseService)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库服务不可用"})
		return
	}

	err := dbSvc.DropColumn(c.Request.Context(), req.TableName, req.ColumnName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "字段删除成功"})
}

func AddColumn(c *gin.Context) {
	var req AddColumnRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	dbSvc, ok := c.MustGet("dbService").(DatabaseService)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库服务不可用"})
		return
	}

	err := dbSvc.AddColumn(c.Request.Context(), req.TableName, req.ColumnName, req.ColumnType, req.Comment)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "字段添加成功"})
}

func AddComment(c *gin.Context) {
	var req AddCommentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	dbSvc, ok := c.MustGet("dbService").(DatabaseService)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据库服务不可用"})
		return
	}

	var sql string
	if req.Column != "" {
		sql = fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'",
			req.TableName, req.Column, strings.ReplaceAll(req.Comment, "'", "''"))
	} else {
		sql = fmt.Sprintf("COMMENT ON TABLE %s IS '%s'",
			req.TableName, strings.ReplaceAll(req.Comment, "'", "''"))
	}

	_, err := dbSvc.Exec(c.Request.Context(), sql)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "字段注释添加成功"})
}

func SetupRoutes(router *gin.Engine) {
	// 数据操作API
	dataGroup := router.Group("/api/data")
	{
		dataGroup.GET("/fetch", FetchData)
		dataGroup.POST("/generate-sql", GenerateInitSQL)
	}

	// 元数据操作API
	metaGroup := router.Group("/api/metadata")
	{
		metaGroup.GET("/tables", GetTables)
		metaGroup.POST("/drop-column", DropColumn)
		metaGroup.POST("/add-column", AddColumn)
		metaGroup.POST("/add-comment", AddComment)
	}
}
